package games.tankwars;

import games.tankwars.behaviors.IntersectAndRemoveBoth;
import games.tankwars.behaviors.IntersectAndStop;
import games.tankwars.behaviors.Launch;
import games.tankwars.behaviors.StaionaryGun;
import games.tankwars.behaviors.TankFollow;
import games.tankwars.behaviors.FollowPrecise;
import games.tankwars.behaviors.TankAI;
import games.tankwars.entities.Bullet;
import games.tankwars.entities.Goal;
import games.tankwars.entities.Gun;
import games.tankwars.entities.MazeElement;
import games.tankwars.entities.MissileLauncher;
import games.tankwars.entities.Tank;

import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Collection;

import vooga.behaviors.AbstractBehavior;
import vooga.behaviors.MoveBehavior;
import vooga.core.AbstractLevel;
import vooga.core.Player;
import vooga.core.VoogaView;
import vooga.entities.Entity;
import vooga.geom.DoubleDimension;
import vooga.geom.Vector;


/**
 * The logic, for the game
 * 
 * created 12-4
 * @author Ben Shelton
 * @author Aneesh Butani
 */
public class Level extends AbstractLevel {
	
	// CONSTANTS
	
	// size of virtual window
	
	final static int WIDTH = 480; // this is arbitrary - what is easiest for everybody to work with?
	final static int HEIGHT = 320;
	final static double TANK_MOVE_SPEED = 2;
	final static double BULLET_MOVE_SPEED =5;
	
	final static Rectangle LEVEL_BOUNDS = new Rectangle(0, 0, WIDTH, HEIGHT);
	
	// NOT CONSTANTS
	
	// state variables
	
	// objects used in game
	Tank myTank;
	Collection<Entity> myBattlefield; // contains all maze elements
	Collection<Entity> myGoals; // all the goal objects you have to blow up to win
	Collection<Entity> myEnemies;
	Collection<Entity> myGuns;
	Collection<Entity> myMissileLaunchers;
	Collection<Entity> myEnemyTanks;
	Tank myEnemy;
	
	public Level(VoogaView view, Player player)
	{
		super(view, player, LEVEL_BOUNDS);
	}
	
	public void init()
	{
		vooga.geom.Vector tankVelocity = new vooga.geom.Vector();

		
//		myTank = (Tank)getFirstEntity("player");
		myBattlefield = getEntities("maze");
		myGoals = getEntities("goals");
		myGuns = getEntities("guns");
		
		myTank = new Tank (new java.awt.geom.Point2D.Double(20,20), new DoubleDimension(20,20),"games/tankwars/images/Tank.jpg");
		
		for (Entity g : myGuns)
			g.addBehavior( new StaionaryGun (myTank, this));
		
		if (getEntities("missiles")!=null)
			{
			myMissileLaunchers = getEntities("missiles");
			for (Entity m : myMissileLaunchers)
				m.addBehavior(new Launch (myTank, this));
			
			}
		
		if (getEntities("enemyTank")!=null)
		{
		myEnemyTanks = getEntities("enemyTank");
		for (Entity m : myEnemyTanks)
			{
			m.addBehavior(new TankFollow (myTank, 60, this));
			m.addBehavior(new TankAI (myTank, this));
			m.addBehavior(new IntersectAndStop(tankVelocity, myBattlefield));
			m.addBehavior(new IntersectAndStop(tankVelocity, myGoals));
			}
		
		}
		
		myTank.addBehavior(new games.tankwars.behaviors.IntersectAndStop(tankVelocity,myBattlefield));
		myTank.addBehavior(new games.tankwars.behaviors.IntersectAndRemoveBoth(tankVelocity,myGoals,this));
		myTank.addBehavior(new MoveBehavior(LEVEL_BOUNDS));
		setPhysicalSize(new java.awt.Dimension(LEVEL_BOUNDS.width * 2, LEVEL_BOUNDS.height * 2));
		
//		MissileLauncher myLauncher = new MissileLauncher (new java.awt.geom.Point2D.Double(200,200), new DoubleDimension (10,10)); 
//		myLauncher.addBehavior (new Launch(myTank, this));
//		addEntity(myLauncher);
		
//		Gun g = new Gun (new java.awt.geom.Point2D.Double(200,200), new DoubleDimension (10,4));
//		g.addBehavior( new StaionaryGun (myTank, this));
//		addEntity(g);
		
//		MazeElement m = new MazeElement (new java.awt.geom.Point2D.Double(100,100), new DoubleDimension (5,2), false);
//		m.addBehavior (new FollowPrecise (myTank, this));
//		addEntity(m);
		
		
//		myEnemy = new Tank (new java.awt.geom.Point2D.Double(200,220), new DoubleDimension(20,20), "games/tankwars/images/tank.jpg");
//		myEnemy.addBehavior(new TankAI(myTank, this));
//		myEnemy.addBehavior(new TankFollow(myTank,3,this));
//		myEnemy.addBehavior((new FollowPrecise (myTank, this)));
//		myEnemy.addBehavior(new games.tankwars.behaviors.IntersectAndStop(tankVelocity,myBattlefield));
//		myEnemy.addBehavior(new games.tankwars.behaviors.IntersectAndStop(tankVelocity, myTank));
		
		addEntity(myTank);
		addEntities(myBattlefield);
		addEntities(myGoals);
		addEntities(myGuns);
		addKeyListener(myKeyAdapter);
		
		// we initialize the game here
	}		
	
	public void handleCollision(Entity entity1, Entity entity2)
	{
		// handle a collision - Jodom writes this
		// I have implemented collisions using behavours
		// this method should not be called
		
		//here is the code to be placed before LevelFactor finishs to handle the collisions
		vooga.geom.Vector tankVelocity = new vooga.geom.Vector();
		
		//Collection<MazeElement> myBattlefield must be initialzed
		//how to create tank behavior
		myTank.addBehavior(new games.tankwars.behaviors.IntersectAndStop(tankVelocity,myBattlefield));
		myTank.addBehavior(new games.tankwars.behaviors.IntersectAndRemove(tankVelocity,myGoals,this));
		
		
		games.tankwars.entities.Bullet bullet;
		vooga.geom.Vector bulletVelocity;
		//bullet.addBehavior(new tankwars.behaviors.IntersectAndRemove(bulletVelocity,myGoals,this));
		
	}
	
	//have to be able to remove goals differently
	public void removeEntity(Entity e)
	{
		super.removeEntity(e);
		if(e instanceof Goal)
			myGoals.remove(e);
		checkLevelOver();
	}
	
	
	protected void checkLevelOver()
	{
		if(myGoals.isEmpty()) // if you've blown up everything
		{
			nextLevel();
		}
		
	}
	/**
	 * checks to see if the first player has no more lives
	 */
	protected void checkGameOver()
	{
		if(!myTank.isVisible()) // for now you can't get blown up
		{
			gameOver();
		}
	}
	
	/**
	 * 
	 * @return this (used to help inner classes)
	 */
	private AbstractLevel getLevel()
	{
		return this;
	}
	
	private KeyAdapter myKeyAdapter = new KeyAdapter() // we have to change this to the new method of dealing with keys, which will be done when time miraculously manifests itself
	// and we also have to accommodate shooting
	{ 
		private boolean myIsLeftDown = false;
		private boolean myIsRightDown = false;
		private boolean myIsUpDown = false;
		private boolean myIsDownDown = false;
				
		public void keyPressed(KeyEvent e)
		{
			if (e.getKeyCode()==KeyEvent.VK_RIGHT)
			{
	//			rotate the tank to the right
				myIsRightDown = true;
			}
			else if (e.getKeyCode()==KeyEvent.VK_LEFT)
			{
	//			rotate the tank to the right
				myIsLeftDown = true;
			}
			if (e.getKeyCode()==KeyEvent.VK_UP)
			{
	//			rotate the tank to the right
				myIsUpDown = true;
			}
			else if (e.getKeyCode()==KeyEvent.VK_DOWN)
			{
	//			rotate the tank to the right
				myIsDownDown = true;
			}
			update();
		}
		
		public void keyReleased(KeyEvent e)
		{
			if (e.getKeyCode()==KeyEvent.VK_RIGHT)
			{
				// stop rotating tank right
				myIsRightDown = false;
			}
			else if (e.getKeyCode()==KeyEvent.VK_LEFT)
			{
				// stop rotating tank left
				myIsLeftDown = false;				
			}
			if (e.getKeyCode()==KeyEvent.VK_UP)
			{
				// stop rotating the tank to the right
				myIsUpDown = false;
			}
			else if (e.getKeyCode()==KeyEvent.VK_DOWN)
			{
				// stop rotating the tank to the right
				myIsDownDown = false;
			}
			
			if(e.getKeyCode()== KeyEvent.VK_SPACE)
			{
				
				Bullet newBullet = new games.tankwars.entities.Bullet((java.awt.geom.Point2D.Double)(myTank.getCenter().clone()));
				newBullet.setVelocity(new Vector(myTank.getHeading(),BULLET_MOVE_SPEED));
				newBullet.addBehavior(new MoveBehavior());
				newBullet.addBehavior(new games.tankwars.behaviors.IntersectAndRemove(newBullet.getVelocity(),myGoals,getLevel()));
				newBullet.addBehavior(new games.tankwars.behaviors.IntersectAndRemoveBoth(newBullet.getVelocity(),myEnemies,getLevel()));
				addEntity(newBullet);
			}
			update();
		}
		
		
		private void update()
		{
			if(myIsLeftDown)
			{
				myTank.setHeading(Vector.LEFT);
				myTank.setVelocity(new Vector(Vector.LEFT, TANK_MOVE_SPEED));
				//myTank.addBehavior(new MoveBehavior(new Vector(Vector.LEFT, TANK_MOVE_SPEED), LEVEL_BOUNDS));
			}
			else if(myIsRightDown)
			{
				myTank.setHeading(Vector.RIGHT);
				myTank.setVelocity(new Vector(Vector.RIGHT, TANK_MOVE_SPEED));
				//myTank.addBehavior(new MoveBehavior(new Vector(Vector.RIGHT, TANK_MOVE_SPEED), LEVEL_BOUNDS));
			}
			else if(myIsUpDown)
			{
				myTank.setHeading(Vector.UP);
				myTank.setVelocity(new Vector(Vector.UP, TANK_MOVE_SPEED));
				//myTank.addBehavior(new MoveBehavior(new Vector(Vector.UP, TANK_MOVE_SPEED), LEVEL_BOUNDS));
			}
			else if(myIsDownDown)
			{
				myTank.setHeading(Vector.DOWN);
				myTank.setVelocity(new Vector(Vector.DOWN, TANK_MOVE_SPEED));
				//myTank.addBehavior(new MoveBehavior(new Vector(Vector.DOWN, TANK_MOVE_SPEED), LEVEL_BOUNDS));
			}
			else myTank.getVelocity().setMagnitude(0);
		}
	};

}
